package com.authsphere.security.common;

import com.authsphere.common.utils.JsonUtils;
import com.authsphere.plugin.api.WebExchange;
import com.authsphere.security.common.utils.BeanValidator;
import com.authsphere.security.web.handler.AuthenticationHandler;
import com.authsphere.security.web.handler.HandleType;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.util.Assert;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
 * @program: AuthSphere
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/11 11:24
 **/
public abstract class AbstractRequestBodyAuthenticationFilter<B> extends AbstractAuthenticationProcessingFilter {
    private final Class<B> requestJsonBodyClass;
    private String moduleName = this.getClass().getSimpleName();
    private final String moduleType;
    private AuthenticationHandler authenticationHandler;

    protected AbstractRequestBodyAuthenticationFilter(String moduleType, String processUrl, Class<B> requestJsonBodyClass) {
        super(processUrl);
        this.moduleType = moduleType;
        this.requestJsonBodyClass = requestJsonBodyClass;
    }

    public AbstractRequestBodyAuthenticationFilter(String moduleType, String processUrl, AuthenticationManager authenticationManager, Class<B> requestJsonBodyClass) {
        super(processUrl, authenticationManager);
        this.moduleType = moduleType;
        this.requestJsonBodyClass = requestJsonBodyClass;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        B requestJsonBody = getRequestJsonBody(request, response);
        BeanValidator.validateObject(requestJsonBody);
        beforeAuthentication(request, response, requestJsonBody);
        Authentication authentication = buildAuthenticationToken(request, response, requestJsonBody);
        Authentication authenticate = this.getAuthenticationManager().authenticate(authentication);
        afterAuthentication(request, response, authenticate, requestJsonBody);
        return authenticate;
    }

    protected void beforeAuthentication(HttpServletRequest request, HttpServletResponse response, Object data) {
        if (authenticationHandler != null) {
            WebExchange exchange = WebExchange.Builder.builder()
                    .request(request)
                    .response(response)
                    .requestBody(data)
                    .build();
            authenticationHandler.handle(exchange, HandleType.BEFORE);
        }
        //        checkAccountLockout(authentication, false);
        // 内部属性设置
//        request.setAttribute(Constants.REQUEST_DATA, data);
//        request.setAttribute(Constants.START_TIME, LocalDateTime.now().getSecond());
//        request.setAttribute(Constants.MODULE_TYPE, moduleType);
//        request.setAttribute(Constants.MODULE_NAME, moduleName);
    }

    protected void afterAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authentication, B data) {
        if (authenticationHandler != null) {
            WebExchange exchange = WebExchange.Builder.builder()
                    .request(request)
                    .response(response)
                    .authentication(authentication)
                    .requestBody(data)
                    .build();
            authenticationHandler.handle(exchange, HandleType.AFTER);
        }
        //        checkAccountLockout(authentication, true);
        // 外部账号绑定
//        this.accountBindService.bind(request, response, authentication);
    }

    protected abstract Authentication buildAuthenticationToken(HttpServletRequest request, HttpServletResponse response, B requestJsonBody);

    public B getRequestJsonBody(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));
        StringBuilder responseStrBuilder = new StringBuilder();
        String inputStr;
        while ((inputStr = streamReader.readLine()) != null) {
            responseStrBuilder.append(inputStr);
        }
        String data = responseStrBuilder.toString();
        return JsonUtils.parse(data, requestJsonBodyClass);
    }

    public void setModuleName(String moduleName) {
        Assert.notNull(moduleName, "moduleName cannot be null");
        this.moduleName = moduleName;
    }

    public String getModuleName() {
        return moduleName;
    }

    public String getModuleType() {
        return moduleType;
    }

    public void setAuthenticationHandler(AuthenticationHandler authenticationHandler) {
        this.authenticationHandler = authenticationHandler;
    }

    //    protected void checkAccountLockout(Authentication authentication, boolean needAuthentication) {
//        if (accountLockoutService != null) {
//            if (needAuthentication) {
//                if (authentication.isAuthenticated()) {
//                    int lockedTime = accountLockoutService.getLockedTime(authentication.getName());
//                    if (lockedTime > 0) {
//                        // 账号被锁定
//                        throw new LockedException(String.format("您的账号已锁定，请等待[%s]分钟后重试", lockedTime));
//                    } else if (lockedTime < 0) {
//                        // 账号永久锁定
//                        throw new LockedException("您的账号已被永久锁定，请联系管理员");
//                    }
//                }
//            } else {
//                int lockedTime = accountLockoutService.getLockedTime(authentication.getName());
//                if (lockedTime > 0) {
//                    // 账号被锁定
//                    throw new LockedException(String.format("您的账号已锁定，请等待[%s]分钟后重试", lockedTime));
//                } else if (lockedTime < 0) {
//                    // 账号永久锁定
//                    throw new LockedException("您的账号已被永久锁定，请联系管理员");
//                }
//            }
//        }
//    }

}
